// ============================================================================
// com.chrishobson.smooth.Smooth
// A simple program adapted from an example in Java in a Nutshell published
// by O'Reilly & Associates
// It shows how to do smooth animation using double buffering. Double buffering
// uses an off-screen image which is drawn into and then quickly put onto the
// screen *without* erasing the old image first. This avoids flicker
//
// It's nothing fancy I just use it as a simple test that Java is up and
// running and that a browser supports the JDK that I have compiled with.
//
// This version is not exactly as given in the book, the book covered
// Java 1.0 and I have update this code to use the new delegation based
// event model introduced in Java 1.1
// ============================================================================

package com.chrishobson.smooth;

import com.chrishobson.awt.Capplet;
import java.awt.*;
import java.awt.event.*;

public class Smooth extends Capplet implements Runnable {
  static final int deltax = 4;
  static final int deltay = 2;

  static final String message = "Smooth Animation";
  int x = 0;
  int y = 0;
  Color c1 = new Color(0x0000ff);
  Color c2 = new Color(0xffffff);
  Font font = new Font("TimeRoman",Font.ITALIC,24);
  Image offscreen;
  int imagewidth, imageheight;
  int stringwidth,stringheight,stringascent;
  Thread animator = null;
  boolean please_stop = false;

  // Measure the size of the text
  public void init() {
    FontMetrics fm = this.getFontMetrics(font);
    stringwidth = fm.stringWidth(message);
    stringheight = fm.getHeight();
    stringascent = fm.getAscent();
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
	// The below line looks complex at first glance, but it's actually
	// quite simple. First (animator != null) is evaluated and assigned
	// to please_stop. If animator is defined please_stop will be TRUE
        // otherwise FALSE. If please_stop is set to FALSE (!please_stop) then
        //  start() is called
        System.out.println("button");
	if(!(please_stop = (animator != null))) start();
      }
    });
  }

  // Start the animation
  public void start() {
    animator = new Thread(this);
    animator.start();
  }

  public void stop() {
    please_stop = true;
    animator = null;
  }

  // Draw a fancy background
  void drawBackground(Graphics gr, Color c1, Color c2, int numsteps) {
    int r,g,b;
    int dr = (c2.getRed() - c1.getRed())/numsteps;
    int dg = (c2.getGreen() - c1.getGreen())/numsteps;
    int db = (c2.getBlue() - c1.getBlue())/numsteps;

    Dimension size = this.getSize();
    int w = size.width, h = size.height;
    int dw = size.width/numsteps;
    int dh = size.height/numsteps;

    gr.setColor(c1);
    gr.fillRect(0,0,w,h);

    for(r = c1.getRed(),g=c1.getGreen(),b=c1.getBlue();
	h > 0;
	h -= dh, w -= dw, r += dr, g+= dg, b+= db) {
        if(r < 0) r = 0;
        if(r > 255) r = 255;
        if(g < 0) g = 0;
        if(g > 255) g = 255;
        if(b < 0) b = 0;
        if(b > 255) b = 255;
      gr.setColor(new Color(r,g,b));
      gr.fillArc(-w,-h,2*w,2*h,0,-90);
    }
  }

  // Draws background and text at current position
  public void paint(Graphics g) {
    drawBackground(g,c1,c2,50);
    g.setColor(Color.black);
    g.setFont(font);
    g.drawString(message,x,y);
  }

  // Run the body of the animator
  public void run() {
    while(!please_stop) {
      Dimension d = this.getSize();
      // Make sure of screen image is correct size
      if(offscreen == null ||
	 (imagewidth != d.width || imageheight != d.height)) {
	offscreen = this.createImage(d.width,d.height);
	imagewidth = d.width;
	imageheight = d.height;
      }

      // Setup clipping
      Rectangle oldrect = new Rectangle(x,y-stringascent,
					stringwidth,stringheight);

      x = ((x + deltax)%d.width);
      y = ((y + deltay)%d.height);

      // New rectangle
      Rectangle newrect = new Rectangle(x,y-stringascent,
					stringwidth,stringheight);

      Rectangle r = newrect.union(oldrect);

      // Use this rectangle to clip
      Graphics g = offscreen.getGraphics();
      g.clipRect(r.x,r.y,r.width,r.height);
      paint(g);

      // Copy to screen
      g = this.getGraphics();
      g.clipRect(r.x,r.y,r.width,r.height);
      g.drawImage(offscreen,0,0,this);
      try {
        Thread.sleep(10);
      } catch(InterruptedException e) {
      }
    }
    animator = null;
  }
}





